﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using ALinq.BBS.DataAccess.Properties;

namespace ALinq.BBS.DataAccess
{
    public class Posts : System.Linq.IQueryable<Post>
    {
        //private IQueryable<Post> source;
        //private Expression<Func<Post, bool>> filter;
        private Func<Database> getDataContext;
        private Func<int> getPostsCount;

        internal Posts(Forum forum)
        {
            var ids = new List<int>();
            var stack = new Stack<Forum>();
            stack.Push(forum);
            while (stack.Count > 0)
            {
                var item = stack.Pop();
                ids.Add(item.ID);
                foreach (var child in item.Children)
                    stack.Push(child);
            }

            Expression<Func<Post, bool>> filter = o => ids.Contains(o.ForumID);
            getDataContext = delegate()
            {
                return forum.DataContext;
            };
            getPostsCount = delegate()
            {
                var count = forum.PostsCount;
                foreach (var child in forum.Children)
                    count = count + child.Posts.Count;

                return count;
            };
            Source = DataContext.Posts.Where(filter);
        }

        internal Posts(User user)
        {
            Expression<Func<Post, bool>> filter = o => o.UserID == user.ID;
            getDataContext = delegate() { return user.DataContext; };
            getPostsCount = delegate() { return user.PostsCount; };
            Source = DataContext.Posts.Where(filter);
        }

        internal Posts(IQueryable<Post> source, Database dc, int postsCount)
        {
            getDataContext = delegate() { return dc; };
            getPostsCount = delegate() { return postsCount; };
            Source = source;
        }


        IQueryable<Post> Source
        {
            get;
            set;
        }

        public int Count
        {
            get
            {
                return this.getPostsCount();
            }
        }




        #region Interface
        IEnumerator<Post> IEnumerable<Post>.GetEnumerator()
        {
            return Source.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Source.GetEnumerator();
        }

        Expression IQueryable.Expression
        {
            get { return Source.Expression; }
        }

        Type IQueryable.ElementType
        {
            get { return Source.ElementType; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return Source.Provider; }
        }
        #endregion

        internal Database DataContext
        {
            get { return getDataContext(); }
        }



        //public void DeleteItems(Post[] posts)
        //{
        //    DataContext.Posts.DeleteAllOnSubmit(posts);
        //}

        //public void DeleteItem(Post post)
        //{
        //    DataContext.Posts.DeleteOnSubmit(post);
        //}



        public PostList GetList(int pageIndex)
        {
            var num1 = Settings.Default.PostListSize * pageIndex;
            var items = this.OrderByDescending(o => o.ID).Skip(num1).Take(Settings.Default.PostListSize).ToArray();
            var result = new PostList(this, items, pageIndex);
            //result.Forum = forum;
            return result;
        }

        public Post Next(Post post)
        {
            return this.FindItems(o => o.ID < post.ID).FirstOrDefault();
        }

        public int PagesCount
        {
            get
            {
                var config = Settings.Default;
                var num = Convert.ToInt32(Math.Ceiling((float)Count / config.PostListSize));
                Debug.Assert(num >= (float)Count / config.PostListSize);
                return num;
            }
        }

        public IQueryable<Post> FindItems(Expression<Func<Post, bool>> predicate)
        {
            var result = this.Where(predicate);
            return result;
        }


    }
}
